﻿using System;
using System.Runtime.Serialization;

namespace HYCodeBase.Algorithm.Octree.Data
{
	[DataContract]
	public struct BoundingBox
	{
        [DataMember]
        public Point Center;// { get; set; }

        [DataMember]
        public Point Extents;// { get; set; }

		public Point Size
		{
			get
			{
				return this.Extents * 2f;
			}
			set
			{
				this.Extents = value * 0.5f;
			}
		}

		public Point Min
		{
			get
			{
				return this.Center - this.Extents;
			}
			set
			{
				this.SetMinMax(value, this.Max);
			}
		}

		public Point Max
		{
			get
			{
				return this.Center + this.Extents;
			}
			set
			{
				this.SetMinMax(this.Min, value);
			}
		}

		public BoundingBox(Point center, Point size)
		{
			this.Center = center;
			this.Extents = size * 0.5f;
		}

		public void SetMinMax(Point min, Point max)
		{
			this.Extents = (max - min) * 0.5f;
			this.Center = min + this.Extents;
		}

		public void Encapsulate(Point point)
		{
			this.SetMinMax(Point.Min(this.Min, point), Point.Max(this.Max, point));
		}

		public void Encapsulate(BoundingBox box)
		{
			this.Encapsulate(box.Center - box.Extents);
			this.Encapsulate(box.Center + box.Extents);
		}

		public void Expand(float amount)
		{
			amount *= 0.5f;
			this.Extents += new Point(amount, amount, amount);
		}

		public void Expand(Point amount)
		{
			this.Extents += amount * 0.5f;
		}

		public bool Contains(Point point)
		{
			return this.Min.X <= point.X && this.Max.X >= point.X && this.Min.Y <= point.Y && this.Max.Y >= point.Y && this.Min.Z <= point.Z && this.Max.Z >= point.Z;
		}

		public bool Intersects(BoundingBox box)
		{
			return this.Min.X <= box.Max.X && this.Max.X >= box.Min.X && this.Min.Y <= box.Max.Y && this.Max.Y >= box.Min.Y && this.Min.Z <= box.Max.Z && this.Max.Z >= box.Min.Z;
		}

		public bool IntersectRay(Ray ray)
		{
			float num;
			return this.IntersectRay(ray, out num);
		}

		public bool IntersectRay(Ray ray, out float distance)
		{
			Point point = new Point(1f / ray.Direction.X, 1f / ray.Direction.Y, 1f / ray.Direction.Z);
			float val = (this.Min.X - ray.Origin.X) * point.X;
			float val2 = (this.Max.X - ray.Origin.X) * point.X;
			float val3 = (this.Min.Y - ray.Origin.Y) * point.Y;
			float val4 = (this.Max.Y - ray.Origin.Y) * point.Y;
			float val5 = (this.Min.Z - ray.Origin.Z) * point.Z;
			float val6 = (this.Max.Z - ray.Origin.Z) * point.Z;
			float num = System.Math.Max(System.Math.Max(System.Math.Min(val, val2), System.Math.Min(val3, val4)), System.Math.Min(val5, val6));
			float num2 = System.Math.Min(System.Math.Min(System.Math.Max(val, val2), System.Math.Max(val3, val4)), System.Math.Max(val5, val6));
			if (num2 < 0f)
			{
				distance = num2;
				return false;
			}
			if (num > num2)
			{
				distance = num2;
				return false;
			}
			distance = num;
			return true;
		}

		public override int GetHashCode()
		{
			return this.Center.GetHashCode() ^ this.Extents.GetHashCode() << 2;
		}

		public override bool Equals(object other)
		{
			bool result;
			if (!(other is BoundingBox))
			{
				result = false;
			}
			else
			{
				BoundingBox boundingBox = (BoundingBox)other;
				result = (this.Center.Equals(boundingBox.Center) && this.Extents.Equals(boundingBox.Extents));
			}
			return result;
		}

		public override string ToString()
		{
			return string.Format("Center: {0}, Extents: {1}", this.Center, this.Extents);
		}

		public string ToString(string format)
		{
			return string.Format("Center: {0}, Extents: {1}", this.Center.ToString(format), this.Extents.ToString(format));
		}

		public static bool operator ==(BoundingBox lhs, BoundingBox rhs)
		{
			return lhs.Center == rhs.Center && lhs.Extents == rhs.Extents;
		}

		public static bool operator !=(BoundingBox lhs, BoundingBox rhs)
		{
			return !(lhs == rhs);
		}
	}
}
